/* input device text */ PRELIMINARY INFORMATION... CURRENTLY UNDER REVIEW. DOESN'T DESCRIBE THE set mouse port FUNCTIONS. MAY CONTAIN MINOR INACCURACIES IN THE SAMPLE PROGRAM SEGMENT. (printed version available approx 11/18/85, reviewed and correct- ed). Rob Peck. Chapter 1 Input Device This chapter describes the Amiga input device, which is a combi- nation of three other devices: keyboard device, gameport device, and timer device. The input device merges separate input event streams from the keyboard, mouse, and timer into a single stream. This single stream can then be interpreted by the prioritized linked list of input handlers that are watching the input stream. 1.1. OVERVIEW The input device is automatically opened by AmigaDOS by any call to open the console device. When the input device is opened, a task, appropriately named ``input.device'', is started. The input device task communicates directly with the keyboard device to obtain raw key inputs. It also communicates with the gameport device to obtain mouse button and mouse movement events and with the timer device to obtain time events. In addition to these event streams, you can also directly input an event to the input device, to be fed to the handler chain. This topic is also covered below. The keyboard device is also accessible directly. However, while the input device task is operating, it attempts to retrieve all incoming keyboard events and add them to the input stream. The gameport device has two units available to it. As you view the Amiga looking at the gameport connectors, connector ``1'' is assigned as the primary mouse input for Intuition and contributes gameport input events to the input event stream. Connector ``2'' is handled by the other gameport unit and is currently unas- signed. Each unit of the gameport device is an exclusive access object, in that you can specify what type of controller is attached. It is then assumed that only one task is sending requests for input from that unit. While the input device task is running, that task expects to read the input from connector 1. Direct use of the gameport device is covered in a separate chapter of this manual. November 13, 1985 - 2 - The timer device provides time events for the input device. It also provides time interval reports for controlling key repeat rate and key repeat threshold. The timer device is a shared- access device and is described in its own separate section. 1.2. INPUT DEVICE COMMANDS The input device allows the following system functions: COMMAND OPERATION OpenDevice() Obtain shared use of the input device. CloseDevice() Relinquish use of the input device. DoIO() Initiate a command, and wait for it to complete. SendIO() Initiate a command, and return immediately. AbortIO() Abort a command already in the queue. Only the Start, Stop, Invalid, and Flush commands have been implemented for this device. All other commands are no- operations. The input device also supports the following device-specific com- mands: Table 1-1: Input Device Commands I/O COMMAND OPERATION IND_WRITEEVENT Propagate an input event stream to all devices IND_ADDHANDLER Add an input-stream handler into the handler chain. IND_REMHANDLER Remove an input-stream handler from the handler chain. IND_SETTHRESH Set the repeating key hold-down time before repeat starts. IND_SETPERIOD Set the period at which a repeating key repeats. IND_SETMPORT Set the gameport port to which the mouse is connected. IND_SETTRIGGER Read conditions that must be met by a mouse before a pending read request will be satisfied. IND_SETMTYPE Set the type of device at the mouse port. The device-specific commands outlined above are described in the following paragraphs. A description of the contents of an input event is given first because the input device deals in input November 13, 1985 - 3 - events. An input event is a data structure that describes: o the class of the event-often describes the device that generated the event o the subclass of the event-space for more information if needed o the code-keycode if keyboard, button information if mouse, others o a qualifier such as ``ALT key also down'', ``key repeat active'' o a position field which contains a data address or a mouse position count. o a time stamp, showing the sequence in which events have occurred o a link-field by which input events are linked together The various types of input events are listed in the include-file devices/inputevent.h. That information is not repeated here. You can find more information about input events in the chapters titled ``Gameport Device'' and ``Console Device''. There is a difference between simply receiving an input event from a device (gameport, keyboard, or console) and actually becoming a handler of an input event stream. A handler is a rou- tine that is passed an input event, and it is up to the handler to decide if it can process the input event. If the handler does not recognize the event, it passes the address of the event as a return value. Because of the input event field called ie_NextEvent, it is pos- sible for the input event to be a pointer to the first event in a linked list of events to be handled. Thus the handler should be designed to handle multiple events if such a link is used. Note that handlers can, themselves, generate new linked lists of events which can be passed down to lower priority handlers. You add a handler to the chain by the command IND_ADDHANDLER. Assuming that you have a properly initialized an IOStdReq block as a result of a call to OpenDevice() (for the input device), here is a typical C-language call to the IND_ADDHANDLER function: November 13, 1985 - 4 - struct Interrupt handlerStuff; handlerStuff.is_Data = &hsData; /* address of its data area */ handlerStuff.is_Code = myhandler; /* address of entry point to handler */ handlerStuff.is_Node.ln_Pri = 51; /* set the priority one step higher than * Intution, so that our handler enters * the chain ahead of Intuition. */ inputRequestBlock.io_Command = IND_ADDHANDLER; inputRequestBlock.io_Data = &handlerStuff; DoIO(&inputRequestBlock); Notice from the above that Intuition is one of the input device handlers and normally distributes all of the input events. Intuition inserts itself at priority position 50. You can choose the position in the chain at which your handler will be inserted by setting the priority field in the list-node part of the inter- rupt data structure you are feeding to this routine. Note also that any processing time expended by a handler sub- tracts from the time available before the next event happens. Therefore, handlers for the input stream must be fast. Rules for Input Device Handlers The following rules should be followed when you are designing an input handler: 1. If an input handler is capable of processing a specific kind of an input event and that event has no links (ie_NextEvent = 0), the handler can end the handler chain by returning a NULL (0) value. 2. If there are multiple events linked together, the handler can feel free to delink an event from the input event chain, thereby passing a shorter list of events to subse- quent handlers. The starting address of the modified list is the return value. 3. If a handler wishes to add new events to the chain that it passes to a lower priority handler, it may initialize memory to contain the new event or event chain. The handler, when it again gets control on the next round of event handling, should assume nothing about the current contents of the memory blocks it attached to the event chain. Lower priority handlers may have modified the November 13, 1985 - 5 - memory as they handled their part of the event. The handler that allocates the memory for this purpose should keep track of the starting address and the size of this memory chunk so that the memory can be returned to the free memory list when it is no longer needed. Your routine should be structured so that it can be called as though from the following assembler language statement: newEventChain = yourHandlerCode(oldEventChain, yourHandlerData); where: o yourHandlerCode is the entry point to your routine, o oldEventChain is the starting address for the current chain of input events, and o newEventChain is the starting address of an event chain which you are passing to the next handler, if any. A NULL (0) value terminates the handling. Memory that you use to describe a new input event that you've added to the event chain is available for re-use or deallocation when the handler is called again or after the IND_REMHANDLER com- mand for the handler is complete. Because IND_ADDHANDLER installs a handler in any position in the handler chain, it can, for example, ignore specific types of input events as well as act upon and modify existing streams of input. It can even create new input events for Intuition or other programs to interpret. You remove a handler from the handler chain with the command IND_REMHANDLER. Assuming that you have a properly initialized IOStdReq block as a result of a call to OpenDevice() (for the input device) and you have already added the handler using IND_ADDHANDLER, here is a typical C-language call to the IND_REMHANDLER function: inputRequestBlock.io_Command = IND_REMHANDLER; inputRequestBlock.io_Data = &handlerStuff; /* tell it which one to remove */ DoIO(&inputRequestBlock); As noted in the overview of this chapter, input events are nor- mally generated by the timer device, keyboard device or gameport device. A user can also generate an input event and send it to the input device. It will then be treated as any other event and passed through to the input handler chain. You can create your November 13, 1985 - 6 - own stream of events, then send them to the input device using the IND_WRITEEVENT command. Here is an example, assuming a correctly initialized input_request_block. The example sends in a single event, which is a phony mouse-movement: struct InputEvent phony; input_request_block.io_Command = IND_WRITEEVENT; input_request_block.io_Flags = 0; input_request_block.io_Length = sizeof(struct InputEvent); input_request_block.io_Data = &phony; phony.ie_NextEvent = NULL; /* only one */ phony.ie_Class = IECLASS_RAWMOUSE; phony.ie_TimeStamp.tv_secs = 0; phony.ie_TimeStamp.tv_micro = 0; phony.ie_Code = IECODE_NOBUTTON; phony.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE; phony.ie_X = 10; phony.ie_Y = 5; /* mouse didn't move, but program made * system think that it did. */ DoIO(&input_request_block); NOTE: This command adds the input event to the end of the current event stream. The system links other events onto the end of this event, thus modifying the contents of the data structure you constructed in the first place. This command sets the timing in seconds and microseconds for the input device to indicate how long a user must hold down a key before it begins to repeat. This command is normally performed by the Preferences tool or by Intuition when it notices that the Preferences have been changed. If you wish, you can call this function. The following typical sequence assumes that you have already correctly initialized the request block by opening the input device: Only the fields shown here need be initialized. struct InputEvent thresh_event; input_request_block.io_Command = IND_SETTHRESH; input_request_block.io_Flags = 0; input_request_block.io_Data = &thresh_event; thresh_event.ie_NextEvent = 0; thresh_event.ie_TimeStamp.tv_secs = 1; /* one second */ thresh_event.ie_TimeStamp.tv_micro = 500000; /* 500,000 microseconds = 1/2 second */ DoIO(&input_request_block); November 13, 1985 - 7 - This command sets the time period between key repeat events once the initial period threshhold has elapsed. Again, it is a com- mand normally issued by Intuition and preset by the Preferences tool. A typical calling sequence is as shown above; change the command number and the timing period values to suit your applica- tion. 1.3. ADVANCED TOPICS-INPUT DEVICE AND INTUITION There are several ways to receive information from the various devices that are part of the input device. The first way is to communicate directly with the device. This way is, as specified above, occasionally undesirable (while the input device task is running). The second way is to become a handler for the stream of events which the input device produces. That method is also shown above. The third method of getting input from the input device is to retrieve the data from the console device or from the IDCMP (Intuition Direct Communications Message Port). If you choose this third method, you should be aware of what hap- pens to input events if your task chooses not to respond to them. If there is no active window and no active console, then input events (key strokes or left button mouse clicks usually) will simply be ignored. If, however, there is an active window (yours), and you choose to simply let the messages pile up without responding to them as quickly as possible, here is what happens: o Another event occurs. If the system has no empty message that it can fill in to report this new event, then memory is dynamically allocated to hold this new information and the new message is transmitted to the message port for the task. o When the task finally responds to the message, the allo- cated memory isn't returned to the system until the win- dow is closed. Therefore, a task that chooses not to respond to its incoming messages for a long period of time can potentially remove a great deal of memory from the system free memory list, making that memory space unavailable to this or other tasks until this task is completed. Thus it is always a good idea to respond to input messages as quickly as possible to maximize the amount of free memory in the system while your task is running. November 13, 1985